home *** CD-ROM | disk | FTP | other *** search
/ Power CD-ROM!! 8 / Power CD-ROM 8.iso / dos / shred / shred.asm < prev    next >
Assembly Source File  |  1994-09-27  |  38KB  |  770 lines

  1. _TEXT          SEGMENT PUBLIC 'CODE'
  2.                ASSUME  CS:_TEXT,DS:_TEXT,ES:_TEXT,SS:_TEXT
  3.                ORG     100H
  4. START:         JMP     MAIN
  5.  
  6. ;              DATA AREA
  7. ;              ---------
  8. SIGNATURE      DB      CR,SPACE,SPACE,SPACE,CR,LF
  9. COPYRIGHT      DB      "SHRED 1.0 (c) 1995 Michael J. Mefford",CR,LF
  10. First_Rights   DB      "First Published in PC Magazine, "
  11.                DB      "January 10, 1995",CR,LF,LF
  12.  
  13. DB       "Syntax:  SHRED [d:] [filespec] [/S] [/F | /D] [/C]",CR,LF,LF
  14. DB       "Insures confidentiality by writing zeros over sensitive data",CR,LF
  15. DB       "/S Subdirectories.",CR,LF
  16. DB       "/F Free space on disk shredded.",CR,LF
  17. DB       "/D Delete only; no shredding.",CR,LF
  18. DB       "/C Confirmation before shredding suppressed."
  19.  
  20. DOUBLE_SPACE   DB      LF
  21. CR_LF          DB      CR,LF,0,CTRL_Z
  22.  
  23. CR             EQU     13
  24. LF             EQU     10
  25. CTRL_Z         EQU     26
  26. SPACE          EQU     32
  27. BOX            EQU     254
  28.  
  29. Y_SCAN         EQU     15H
  30. N_SCAN         EQU     31H
  31. ESC_SCAN       EQU     01H
  32. CTRL_C         EQU     03H
  33. ENTER_SCAN     EQU     1CH
  34. DIRECTORY      EQU     10H
  35.  
  36. MATCHING       STRUC
  37. RESERVED       DB      21 DUP (?)
  38. ATTRIBUTE      DB      ?
  39. FILE_TIME      DW      ?
  40. FILE_DATE      DW      ?
  41. SIZE_LOW       DW      ?
  42. SIZE_HIGH      DW      ?
  43. FILE_NAME      DB      13 DUP (?)
  44. MATCHING       ENDS
  45.  
  46. BYTES_PER_CLUSTER  DW  ?
  47. AVAILABLE_HIGH     DW  ?
  48. AVAILABLE_LOW      DW  ?
  49.  
  50. ZERO_SEG       DW      ?
  51. CTRL_BREAK     DB      ?
  52. CURRENT_DISK   DB      ?
  53. FILESPEC       DW      ?
  54. DIRECTORY_LINE DW      ?
  55. OPEN_FORMAT    DW      3C00H                   ;Create file.
  56.  
  57. SWITCH_FLAG    DB      0
  58. SUBDIRS        EQU     01H
  59. FREE           EQU     02H
  60. DELETE_ONLY    EQU     04H
  61. CONFIRM        EQU     08H
  62. DISK           EQU     10H
  63.  
  64. NOT_FOUND      DB      CR,LF,"File not found",0
  65. NOT_ENOUGH     DB      "Not enough memory",0
  66. DIRECTORY_OF   DB      "Directory of ",0
  67. SHREDDING      DB      "Shredding ",0
  68. DELETING       DB      "Deleting ",0
  69. FREE_SPACE     DB      "All the FREE space of drive ",0
  70. WILL_BE        DB      "will be ",0
  71. SHREDDED       DB      "shredded.  ",0
  72. DELETED        DB      "deleted.  ",0
  73. WORKING        DB      "... working",0
  74. WARNING        DB      "WARNING: ",0
  75. CONTINUE       DB      "Continue?  (Y/N or Esc to Quit) ",0
  76. TO_CONFIRM     DB      CR,LF,"(Press ",17,217," to confirm, Esc to cancel) ",0
  77. ABORTED        DB      CR,LF,LF,"Aborted",CR,LF,0
  78. TEMP           DB      "SHRED.TMP",0
  79. STAR_DOT_STAR  DB      "*.*",0
  80. DOT_DOT        DB      "..",0
  81. PROTECTED_FILE DB      "is a read-only and can't be shredded.  Press any key.",0
  82.  
  83. ;              CODE AREA
  84. ;              ---------
  85.  
  86. MAIN           PROC    NEAR
  87.                CLD                             ;String moves forward.
  88.                MOV     AX,500H
  89.                INT     10H                     ;Select active page zero.
  90.  
  91.                MOV     AH,0FH
  92.                INT     10H                     ;Get current video mode.
  93.                CMP     AL,7                    ;If it's MONO,
  94.                JZ      CK_CURSOR
  95.                CMP     AL,2                    ; CO80,
  96.                JZ      CK_CURSOR
  97.                CMP     AL,3                    ; or BW80, then OK mode.
  98.                JZ      CK_CURSOR
  99.                MOV     AX,3                    ;Else, change to CO80.
  100.                INT     10H
  101.  
  102. CK_CURSOR:     CALL    GET_CURSOR              ;Read cursor position.
  103.                CMP     DH,1                    ;If DOS prompt already
  104.                JZ      SIGN_ON                 ; at top, skip move.
  105.  
  106.                MOV     AH,8                    ;Else, read attr/char
  107.                INT     10H                     ; at cursor position.
  108.                MOV     BH,AH                   ;Move DOS command line to top
  109.                XOR     CX,CX                   ; of screen by scrolling active
  110.                MOV     DL,80 - 1               ; page with current attribute.
  111.                MOV     AL,DH
  112.                DEC     AL
  113.                MOV     AH,6
  114.                INT     10H
  115.  
  116. SIGN_ON:       MOV     DX,100H                 ;Set cursor to line 2 (logical 1)
  117.                CALL    SET_CURSOR
  118.                MOV     SI,OFFSET SIGNATURE     ;And display copyright
  119.                CALL    PRINT_STRING            ; and syntax.
  120.  
  121.                MOV     BX,OFFSET ZEROS         ;Allocate memory for code, stack
  122.                ADD     BX,15                   ; and 64K for a segment of zeros.
  123.                MOV     CL,4
  124.                SHR     BX,CL
  125.                MOV     AX,DS
  126.                ADD     AX,BX
  127.                MOV     ZERO_SEG,AX             ;Save address of segment of zeros
  128.                ADD     BX,4096
  129.                MOV     AH,4AH
  130.                INT     21H
  131.                JNC     SETUP_STACK
  132.                MOV     SI,OFFSET NOT_ENOUGH    ;Error msg if not enough memory.
  133.                JMP     MSG_EXIT
  134.  
  135. SETUP_STACK:   MOV     SP,OFFSET STACK_PTR     ;Move stack pointer down.
  136.                MOV     DX,OFFSET DTA           ;To preserve command line, change 
  137.                MOV     AH,1AH                  ; DTA from PSP to end of code.
  138.                INT     21H
  139.  
  140.                MOV     ES,ZERO_SEG             ;Fill extra segment with zeros.
  141.                XOR     DI,DI
  142.                XOR     AX,AX
  143.                MOV     CX,32768
  144.                REP     STOSW
  145.                PUSH    CS
  146.                POP     ES
  147.  
  148.                MOV     AX,3300H                ;Retrieve current Ctrl
  149.                INT     21H                     ; break state and store.
  150.                MOV     CTRL_BREAK,DL
  151.                XOR     DL,DL
  152.                MOV     AX,3301H                ;Turn Ctrl break off.
  153.                INT     21H
  154.  
  155.                MOV     AH,19H                  ;Get current drive
  156.                INT     21H
  157.                MOV     CURRENT_DISK,AL         ; and save.
  158.  
  159. ;----------------------------------------------;
  160. PARSE:         MOV     SI,81H                  ;Point to command line parameter.
  161. FIND_SWITCH:   LODSB                           ;Get a byte.
  162.                CMP     AL,CR                   ;Carriage return marks end.
  163.                JZ      FIND_FILESPEC           ;If end, done here.
  164.                CMP     AL,"/"                  ;Is it a switch character?
  165.                JNZ     FIND_SWITCH             ;If no, next byte.
  166.                LODSB                           ;Else, retrieve switch.
  167.                AND     AL,5FH                  ;Else, capitalize.
  168.                CMP     AL,"S"                  ;Is it subdirectories?
  169.                JNZ     CK_FREE                 ;If no, check free switch.
  170.                OR      SWITCH_FLAG,SUBDIRS     ;Else, flag to do subdirectories.
  171. CK_FREE:       CMP     AL,"F"                  ;Is it disk free switch?
  172.                JNZ     CK_DELETE               ;If no, check delete switch.
  173.                OR      SWITCH_FLAG,FREE        ;Else, flag to zero free space.
  174. CK_DELETE:     CMP     AL,"D"                  ;Is it delete-only switch?
  175.                JNZ     CK_CONFIRM              ;If no, check confirm switch.
  176.                OR      SWITCH_FLAG,DELETE_ONLY ;Else, flag to delete-only.
  177. CK_CONFIRM:    CMP     AL,"C"                  ;Is it suppress confirm switch?
  178.                JNZ     BAD_SWITCH              ;If no, exit.
  179.                OR      SWITCH_FLAG,CONFIRM     ;Else, flag to suppress prompts.
  180.                JMP     FIND_SWITCH             ;Next switch.
  181. BAD_SWITCH:    MOV     AL,1
  182.                JMP     RESTORE
  183.  
  184. ;------------------------------------------------------------------;
  185. ; Parse drive and/or path delimiters.  Convert filespec to ASCIIZ. ;
  186. ; If drive delimiter found (:), change to requested drive.         ;
  187. ;------------------------------------------------------------------;
  188. FIND_FILESPEC: MOV     SI,81H                  ;Point to command line parameter.
  189. PARSE_LEADING: LODSB                           ;Get a byte.
  190.                CMP     AL,SPACE                ;Is it a space char or below?
  191.                JA      LEADING_END             ;If no, done here.
  192.                CMP     AL,CR                   ;Is it carriage return?
  193.                JNZ     PARSE_LEADING           ;If no, get next byte.
  194. LEADING_END:   DEC     SI                      ;Adjust pointer to string start.
  195.                MOV     BP,SI                   ;Save start of filespec.
  196.                MOV     BX,SI                   ;Use BX as filename start pointer
  197.  
  198. FIND_END:      LODSB                           ;Get a byte.
  199.                CMP     AL,":"                  ;Is it a drive delimiter?
  200.                JNZ     CK_SLASH                ;If no, check path delimiter.
  201.                MOV     DL,[SI-2]               ;Else, retrieve drive specifier.
  202.                AND     DL,5FH                  ;Capitalize.
  203.                SUB     DL,"A"                  ;Convert to DOS format.
  204.                MOV     AH,0EH                  ;Change drive.
  205.                INT     21H
  206.                MOV     BX,SI                   ;Save as filename start.
  207.                JMP     FIND_END                ;Continue parsing.
  208.  
  209. CK_SLASH:      CMP     AL,"\"                  ;Is it a path delimiter?
  210.                JNZ     CK_DELIMITER            ;If no, check switch character.
  211.                MOV     BX,SI                   ;Else, save as filename start.
  212. CK_DELIMITER:  CMP     AL,"/"                  ;Is it a switch delimiter?
  213.                JZ      FOUND_END               ;If yes, end of filespec.
  214.                CMP     AL,SPACE                ;Is it above space character?
  215.                JA      FIND_END                ;If yes, continue until find end.
  216.  
  217. FOUND_END:     DEC     SI                      ;Adjust.
  218.                PUSH    SI                      ;Save filespec end.
  219.                PUSH    BX                      ;Save filespec start.
  220.                MOV     BYTE PTR [SI],0         ;Convert to ASCIIZ.
  221.                CMP     BP,SI                   ;Any filespec?
  222.                JZ      NO_SPEC                 ;If no, treat as /F.
  223.                CMP     BYTE PTR [SI - 1],":"   ;Drive specifier only?
  224.                JNZ     GET_CURRENT             ;If no, skip
  225. NO_SPEC:       OR      SWITCH_FLAG,DISK
  226.  
  227. GET_CURRENT:   MOV     SI,OFFSET CURRENT_DIR   ;Retrieve current directory.
  228.                CALL    GET_DIR
  229.                MOV     AH,19H                  ;Retrieve current disk.
  230.                INT     21H
  231.                ADD     AL,"A"                  ;Convert to ASCII.
  232.                MOV     BYTE PTR WORKING_DIR,AL         ;Save drive
  233.                MOV     BYTE PTR WORKING_DIR + 1,":"    ; and colon delimiter.
  234.  
  235.                CALL    GET_AVAILABLE              ;Get disk free space.
  236.  
  237.                TEST    SWITCH_FLAG,FREE OR DISK   ;Was there /F or no filespec
  238.                JZ      FIND_PATH                  ; or drive-only?; If no, skip.
  239.                TEST    SWITCH_FLAG,DELETE_ONLY    ;Was there /D delete only?
  240.                JNZ     FIND_PATH                  ;If yes, skip.
  241.                CALL    SHRED_FREE                 ;Else, shred free disk space.
  242.                MOV     SI,OFFSET DOUBLE_SPACE     ;Add double space
  243.                CALL    PRINT_STRING               ; between outputs.
  244.  
  245. ;-------------------------------------------------;
  246. FIND_PATH:     POP     BX                      ;Retrieve filename start.
  247.                POP     SI                      ;Retrieve filespec end.
  248.                TEST    SWITCH_FLAG,DISK        ;Was filespec drive-only?
  249.                JZ      CK_ROOT                 ;If no, continue.
  250.                JMP     GOOD_EXIT               ;Else, done.
  251.  
  252. CK_ROOT:       MOV     CX,1                    ;CX=1:"\"not=root; CX=0:"\"=root.
  253.                CMP     BYTE PTR [BX - 1],"\"   ;Filespec start path delimiter?
  254.                JNZ     CK_PATH                 ;If no, not root.
  255.                CMP     BYTE PTR [BX - 2],":"   ;Else, is it prefaced with colon?
  256.                JZ      ROOT                    ;If yes, then root.
  257.                CMP     BYTE PTR [BX - 2],SPACE ;Is it prefaced with white space?
  258.                JA      CK_TRAILING             ;If no, then trailing slash?
  259. ROOT:          DEC     CX                      ;Else, root; CX=0 for root flag.
  260.                JMP     SHORT CK_PATH           ;Change default path.
  261.  
  262. CK_TRAILING:   CMP     BX,SI                   ;Filename start = filespec end?
  263.                JNZ     CK_PATH                 ;If no, not trailing slash.
  264.                MOV     BYTE PTR [BX - 1],0     ;Else, zero out trailing slash
  265.                MOV     BX,OFFSET STAR_DOT_STAR ; and use global filespec.
  266.  
  267. CK_PATH:       MOV     DX,BP                   ;See if filespec is a path
  268.                CALL    CHANGE_DIR              ; by changing directory.
  269.                JC      CK_FILESPEC             ;If failed, remove filename.
  270.                MOV     BX,OFFSET STAR_DOT_STAR ;Else, use global for filename.
  271.                JMP     SHORT GOT_FILESPEC      ;Done here.
  272.  
  273. CK_FILESPEC:   JCXZ    SAVE_DELIMIT            ;Is path root?; If yes leave "\".
  274.                DEC     BX                      ;Else, point to slash.
  275. SAVE_DELIMIT:  PUSH    [BX]                    ;Preserve filename start.
  276.                MOV     BYTE PTR [BX],0         ;Temp ASCIIZ twixt path and name.
  277.                CALL    CHANGE_DIR              ;Change directory.
  278.                POP     [BX]                    ;Restore first byte of filename.
  279.                JCXZ    GOT_FILESPEC            ;If root, done here.
  280.                INC     BX                      ;Else, readjust filename pointer.
  281. GOT_FILESPEC:  MOV     FILESPEC,BX             ;Save filename.
  282.  
  283. ;----------------------------------------------;
  284.                MOV     BP,OFFSET TREE_LEVEL    ;Initialize directory tree
  285.                MOV     DI,BP                   ; level array to level one.
  286.                MOV     AX,0101H
  287.                MOV     CX,50
  288.                REP     STOSW
  289.                CALL    GET_CURSOR              ;Get relative line for
  290.                MOV     DIRECTORY_LINE,DX       ; directory display.
  291.                MOV     OPEN_FORMAT,3D01H       ;Open file for writing.
  292.  
  293. NEXT_LEVEL:    MOV     SI,OFFSET WORKING_DIR + 2  ;Display current directory.
  294.                CALL    GET_DIR
  295.                MOV     SI,OFFSET DIRECTORY_OF
  296.                CALL    PRINT_STRING
  297.                MOV     SI,OFFSET WORKING_DIR
  298.                CALL    PRINT_STRING
  299.  
  300. FIND_FIRST:    MOV     DX,FILESPEC             ;Find first matching normal
  301.                XOR     CX,CX                   ; file to filespec.
  302.                MOV     AH,4EH
  303.                INT     21H
  304.                JNC     CK_READ_ONLY
  305.                MOV     SI,OFFSET NOT_FOUND     ;If failed, display message.
  306.                CALL    PRINT_STRING
  307.                JMP     SHORT CK_SUBDIRS        ;Check /Subdir switch.
  308.  
  309. FIND_NEXT:     MOV     AH,4FH                  ;Find next matching file.
  310.                INT     21H
  311.                JC      CK_SUBDIRS              ;If failed, check /Subdir switch.
  312.  
  313. CK_READ_ONLY:  TEST    BYTE PTR DTA.ATTRIBUTE, 1
  314.                JZ      CK_WARNING
  315.                MOV     DX,DIRECTORY_LINE
  316.                INC     DH
  317.                CALL    BLANK_LINE
  318.                CALL    DISPLAY_NAME
  319.                MOV     SI,OFFSET PROTECTED_FILE
  320.                CALL    PRINT_STRING
  321.                CALL    CLEAR_KEY
  322.                CALL    GET_KEY
  323.                JMP     FIND_NEXT
  324.  
  325. CK_WARNING:    MOV     DX,DIRECTORY_LINE       ;Move cursor to line below
  326.                INC     DH                      ; directory.
  327.                CALL    BLANK_LINE              ;Blank out last display.
  328.                TEST    SWITCH_FLAG,CONFIRM     ;Did user suppress prompts?
  329.                JNZ     NO_WARNING              ;If yes, no warning.
  330.                MOV     SI,OFFSET WARNING       ;Else, display warning message.
  331.                CALL    PRINT_STRING
  332.                CALL    DISPLAY_NAME            ;Display complete stats of file.
  333.                MOV     SI,OFFSET WILL_BE
  334.                CALL    PRINT_STRING            ;Display message.
  335.                TEST    SWITCH_FLAG,DELETE_ONLY
  336.                JZ      MESSAGE1
  337.                MOV     SI,OFFSET DELETED
  338. MESSAGE1:      CALL    PRINT_STRING
  339.                CALL    PROMPT                  ;Ask user if should continue.
  340.                JC      FIND_NEXT               ;If no, find next matching.
  341.                CALL    SHRED_FILE              ;Else, shred the file.
  342.                JMP     FIND_NEXT               ;Find next matching file.
  343.  
  344. NO_WARNING:    CALL    CK_KEY                  ;Let user abort the /C suppress
  345.                JNZ     ERROR_EXIT              ; confirm mode with any keypress.
  346.                MOV     SI,OFFSET SHREDDING     ;Display message
  347.                TEST    SWITCH_FLAG,DELETE_ONLY
  348.                JZ      MESSAGE2
  349.                MOV     SI,OFFSET DELETING
  350. MESSAGE2:      CALL    PRINT_STRING
  351.                CALL    DISPLAY_NAME            ; and file stats.
  352.                CALL    SHRED_FILE              ;Shred the file.
  353.                JMP     FIND_NEXT               ;Next matching.
  354.  
  355. ;----------------------------------------------;
  356. CK_SUBDIRS:    TEST    SWITCH_FLAG,SUBDIRS     ;Was there a /Subdir switch?
  357.                JNZ     FIRST_DIR               ;If yes, continue.
  358.                JMP     SHORT GOOD_EXIT         ;Else, exit.
  359.  
  360. PARENT_DIR:    CMP     BP,OFFSET TREE_LEVEL    ;Are we at tree level where we
  361.                JZ      GOOD_EXIT               ; started? If yes, done here.
  362.                MOV     BYTE PTR [BP],1         ;Else, first dir of this level.
  363.                DEC     BP                      ;Go down a level.
  364.                MOV     DX,OFFSET DOT_DOT       ;Change to parent directory.
  365.                CALL    CHANGE_DIR
  366.  
  367. FIRST_DIR:     XOR     BL,BL                   ;BL = directory number.
  368.                MOV     DX,OFFSET STAR_DOT_STAR ;Global search.
  369.                MOV     CX,DIRECTORY            ;Ask for directories.
  370.                MOV     AH,4EH
  371.                INT     21H
  372.                JC      PARENT_DIR              ;If no match, down a level.
  373.                JMP     SHORT CK_DIR            ;Else, see if it's a directory.
  374.  
  375. NEXT_DIR:      MOV     AH,4FH                  ;Get all subdirectories in
  376.                INT     21H                     ; current directory then
  377.                JC      PARENT_DIR              ; to parent.
  378.  
  379. CK_DIR:        CMP     BYTE PTR DTA.ATTRIBUTE,DIRECTORY  ;Is it a directory?
  380.                JNZ     NEXT_DIR                          ;If no, next matching.
  381.                CMP     BYTE PTR DTA.FILE_NAME,'.'        ;is it a dot directory?
  382.                JZ      NEXT_DIR                          ;If no, next matching.
  383.                INC     BL                      ;Increment position in directory.
  384.                CMP     BL,[BP]                 ;Continue until new directory.
  385.                JNZ     NEXT_DIR
  386.                INC     BYTE PTR DS:[BP]        ;Update this level dir count.
  387.                MOV     DX,OFFSET DTA.FILE_NAME
  388.                CALL    CHANGE_DIR              ;Change the directory.
  389.                INC     BP                      ;Up a level.
  390.                MOV     DX,DIRECTORY_LINE       ;Blank out last display.
  391.                CALL    BLANK_LINE
  392.                JMP     NEXT_LEVEL              ;Get all files in new directory.
  393.  
  394. ;----------------------------------------------;
  395. ERROR_EXIT:    MOV     SI,OFFSET ABORTED       ;Display abort message.
  396. MSG_EXIT:      CALL    PRINT_STRING
  397.                MOV     AL,1                    ;ERRORLEVEL = 1.
  398.                JMP     SHORT RESTORE           ;Restore defaults.
  399.  
  400. GOOD_EXIT:     XOR     AL,AL                   ;ERRORLEVEL = 0.
  401.  
  402. RESTORE:       PUSH    AX                      ;Save ERRORLEVEL.
  403.                MOV     DL,CTRL_BREAK           ;Restore break state.
  404.                MOV     AX,3301H
  405.                INT     21H
  406.                MOV     DX,OFFSET CURRENT_DIR   ;Restore default directory.
  407.                CALL    CHANGE_DIR
  408.                MOV     DL,CURRENT_DISK         ;Restore default drive.
  409.                MOV     AH,0EH
  410.                INT     21H
  411.                POP     AX                      ;Retrieve ERRORLEVEL.
  412. EXIT:          MOV     AH,4CH
  413.                INT     21H                     ;Terminate.
  414. MAIN           ENDP
  415.  
  416.                ;***************;
  417.                ;* SUBROUTINES *;
  418.                ;***************;
  419. SHRED_FREE:    PUSH    BP                      ;Preserve base pointer.
  420.                MOV     DX,OFFSET TEMP          ;See if temporary file exits.
  421.                MOV     CX,1FH                  ;Use all attributes.
  422. NEXT_TEMP:     MOV     AH,4EH
  423.                INT     21H
  424.                JC      GOT_TEMP                ;If it doesn't, OK.
  425.                MOV     BX,DX
  426.                INC     BYTE PTR [BX]           ;Else, change name.
  427.                JNZ     NEXT_TEMP               ;Give up after several name
  428.                JMP     ERROR_EXIT              ; changes and abort.
  429.  
  430. GOT_TEMP:      MOV     BP,DX                   ;Point to temporary filename.
  431.                TEST    SWITCH_FLAG,CONFIRM     ;Do we need user permission to
  432.                JNZ     NO_PROMPT               ; continue? If no, no prompt.
  433.  
  434.                CALL    FREE_MSG                ;Else, display message.
  435.                MOV     SI,OFFSET WILL_BE
  436.                CALL    PRINT_STRING
  437.                MOV     SI,OFFSET WILL_BE
  438.                CALL    PRINT_STRING
  439.                CALL    PRINT_STRING
  440.                MOV     SI,OFFSET CR_LF
  441.                CALL    PRINT_STRING
  442.                CALL    PROMPT                  ;Ask user if should continue.
  443.                JC      FREE_END                ;If no, done here.
  444.                JMP     SHORT DO_FREE           ;Else, shred the disk free space.
  445.  
  446. NO_PROMPT:     CALL    CK_KEY                  ;Let user abort the /C suppress
  447.                JNZ     ERROR_EXIT              ; confirm mode with any keypress.
  448.                MOV     SI,OFFSET SHREDDING     ;Display message.
  449.                CALL    PRINT_STRING
  450.                CALL    FREE_MSG
  451.                MOV     SI,OFFSET WORKING       ;Display "... working" message.
  452.                CALL    PRINT_STRING
  453.  
  454. DO_FREE:       MOV     SI,AVAILABLE_HIGH       ;Create a temporary file and
  455.                MOV     DI,AVAILABLE_LOW        ; write zeros bytes equal to
  456.                CALL    WRITE_ZEROS             ; the amount of free space.
  457. FREE_END:      POP     BP                      ;Restore base pointer.
  458.                RET
  459.  
  460. ;----------------------------------------------;
  461. FREE_MSG:      MOV     SI,OFFSET FREE_SPACE    ;Display free space message.
  462.                CALL    PRINT_STRING
  463.                MOV     AL,BYTE PTR WORKING_DIR ;Display the working drive.
  464.                MOV     AH,0EH
  465.                INT     10H
  466.                MOV     AX,0EH SHL 8 + SPACE
  467.                INT     10H
  468.                RET
  469.  
  470. ;----------------------------------------------;
  471. SHRED_FILE:    PUSH    BP                      ;Preserve base pointer.
  472.                MOV     BP,OFFSET DTA.FILE_NAME ;Point to filename.
  473.                MOV     SI,DTA.SIZE_HIGH        ;Retrieve size of file.
  474.                MOV     DI,DTA.SIZE_LOW
  475.                MOV     DX,SI
  476.                MOV     AX,DI
  477.                MOV     CX,BYTES_PER_CLUSTER    ;Round up file size to nearest
  478.                DIV     CX                      ; whole cluster by dividing by
  479.                SUB     CX,DX                   ; bytes per cluster and
  480.                ADD     DI,CX                   ; adding remainder to size.
  481.                ADC     SI,0
  482.                CALL    WRITE_ZEROS             ;Write zeros over the file.
  483.                POP     BP                      ;Restore base pointer.
  484.                RET
  485.  
  486. ;---------------------------------------------------------------;
  487. ; INPUT: BP -> filename; SI:DI = number of zero bytes to write. ;
  488. ;---------------------------------------------------------------;
  489. WRITE_ZEROS:   TEST    SWITCH_FLAG,DELETE_ONLY ;Is the delete-only flag set?
  490.                JNZ     DELETE_FILE             ;If yes, don't write zeros.
  491.                MOV     DX,BP                   ;Filename pointer.
  492.                XOR     CX,CX                   ;Normal attribute.
  493.                MOV     AX,OPEN_FORMAT          ;Create new or open existing.
  494.                INT     21H
  495.                JC      WRITE_FAIL              ;If failed, exit.
  496.                MOV     BX,AX                   ;Else, save filehandle.
  497.  
  498. NEXT_WRITE:    MOV     CX,DI                   ;Retrieve low half of byte count.
  499.                OR      SI,SI                   ;Is high half zero?
  500.                JZ      SUBTRACT                ;If yes, continue.
  501.                MOV     CX,0FFFFH               ;Else, write full word (65535).
  502. SUBTRACT:      SUB     DI,CX                   ;Subtract from running count.
  503.                SBB     SI,0                    ;If borrow, adjust high half.
  504.                JCXZ    CLOSE_FILE              ;If zero bytes, done here.
  505.  
  506.                PUSH    DS                      ;Preserve data segment.
  507.                MOV     DS,ZERO_SEG             ;Use segment of zeros.
  508.                XOR     DX,DX                   ;Offset of zero.
  509.                MOV     AH,40H                  ;Write to file.
  510.                INT     21H
  511.                POP     DS                      ;Restore data segment.
  512.                JC      WRITE_FAIL              ;If failed, exit.
  513.                CMP     AX,CX                   ;Did we write what we asked?
  514.                JNZ     WRITE_FAIL              ;If no, failed; exit.
  515.                JMP     NEXT_WRITE              ;Else, write next chunk.
  516.  
  517. CLOSE_FILE:    MOV     AH,3EH                  ;Close file.
  518.                INT     21H
  519.                JC      WRITE_FAIL              ;If failed, exit.
  520. DELETE_FILE:   MOV     DX,BP
  521.                MOV     AH,41H                  ;Delete file.
  522.                INT     21H
  523.                JC      WRITE_FAIL              ;If failed, exit.
  524. ZEROS_END:     RET
  525.  
  526. WRITE_FAIL:    MOV     DX,OFFSET NOT_FOUND     ;With all failures, display
  527.                CALL    PRINT_STRING            ; generic "file not found"
  528.                JMP     ERROR_EXIT              ; message and abort.
  529.  
  530. ;----------------------------------------------------------------------;
  531. ; OUTPUT: CY = 0: Yes; CY = 1: No;  If Esc or ^C, go directly to exit. ;
  532. ;----------------------------------------------------------------------;
  533. PROMPT:        MOV     SI,OFFSET CONTINUE      ;Display message.
  534.                CALL    PRINT_STRING
  535.                CALL    CLEAR_KEY               ;Clear keyboard buffer.
  536. GET_INPUT:     CALL    GET_KEY                 ;Now get a keystroke.
  537.                CMP     AH,Y_SCAN               ;Was it "Y"?
  538.                JNZ     CK_NO
  539.                MOV     AH,0EH                  ;If yes, display "Y" and
  540.                INT     10H
  541.                CALL    PRINT_STRING            ; ask for confirmation.
  542. GET_CONFIRM:   CALL    GET_KEY
  543.                CMP     AH,ESC_SCAN
  544.                STC
  545.                JZ      PROMPT_END
  546.                CMP     AH,ENTER_SCAN
  547.                JNZ     GET_CONFIRM
  548.                MOV     SI,OFFSET WORKING
  549.                CALL    PRINT_STRING
  550.                CLC
  551.                JMP     SHORT PROMPT_END
  552.  
  553. CK_NO:         CMP     AH,N_SCAN               ;Was it "N"?
  554.                STC
  555.                JZ      PROMPT_END
  556.                CMP     AH,ESC_SCAN             ;Was it Esc?
  557.                JZ      BREAK
  558.                OR      AH,AH                   ;Was it Ctrl Break?
  559.                JZ      BREAK
  560.                CMP     AL,CTRL_C               ;Was it Ctrl C?
  561.                JNZ     GET_INPUT               ;If Esc, Ctrl Break or Ctrl C,
  562. BREAK:         JMP     ERROR_EXIT              ; immediate exit.
  563. PROMPT_END:    RET                             ;Else, return keystroke.
  564.  
  565. ;----------------------------------------------;
  566. GET_AVAILABLE: XOR     DL,DL                   ;Default drive.
  567.                MOV     AH,36H                  ;Get disk free space.
  568.                INT     21H
  569.                MUL     CX                      ;Bytes/sector * sectors/cluster
  570.                MOV     BYTES_PER_CLUSTER,AX    ; equals bytes/cluster.
  571.                MUL     BX                      ;Avail clusters * bytes/cluster
  572.                MOV     AVAILABLE_HIGH,DX       ; equals available bytes.
  573.                MOV     AVAILABLE_LOW,AX
  574.                RET
  575.  
  576. ;----------------------------------------------;
  577. DISPLAY_NAME:  MOV     SI,OFFSET DTA.FILE_NAME ;Point to filename.
  578.                MOV     DI,OFFSET RESULTS       ;And storage area.
  579.                MOV     AX,SPACE SHL 8 + SPACE  ;Initiate storage with spaces.
  580.                MOV     CX,20
  581.                REP     STOSW
  582.                MOV     DI,OFFSET RESULTS       ;Point to start of storage again.
  583.                MOV     CX,12                   ;Store 12 bytes of filename.
  584. NEXT_STORE:    LODSB                           ;Get a byte.
  585.                OR      AL,AL                   ;End of filename?
  586.                JZ      END_STORE               ;If yes, finish with blanks.
  587.                CMP     AL,"."                  ;Is it the period?
  588.                JNZ     STORE_BYTE              ;If no, store.
  589.                SUB     CX,3                    ;Else store 3 spaces.
  590.                MOV     AL,SPACE
  591.                REP     STOSB
  592.                ADD     CX,3
  593.                JMP     SHORT NEXT_STORE        ;Get next byte.
  594.  
  595. STORE_BYTE:    STOSB                           ;Store byte.
  596.                LOOP    NEXT_STORE              ;Get next byte.
  597. END_STORE:     MOV     AL,SPACE                ;Pad balance with spaces.
  598.                REP     STOSB
  599.  
  600.                PUSH    DI                      ;Save pointer.
  601.                ADD     DI,8                    ;Move to end of bytes field.
  602.                MOV     DX,DTA.SIZE_LOW         ;Retrieve high and low words
  603.                MOV     AX,DTA.SIZE_HIGH        ; of size in bytes.
  604.                MOV     BX,10                   ;Convert to decimal.
  605.                STD                             ;Reverse direction.
  606.  
  607. NEXT_SIZE:     MOV     CX,DX                   ;Low word in CX.
  608.                XOR     DX,DX                   ;Zero in high half.
  609.                DIV     BX                      ;Convert to decimal.
  610.                XCHG    AX,CX                   ;Retrieve low word.
  611.                DIV     BX
  612.                XCHG    AX,DX                   ;Retrieve remainder.
  613.                ADD     AL,"0"                  ;Convert to ASCII.
  614.                STOSB                           ;Store it.
  615.                MOV     AX,CX                   ;Are we done?
  616.                OR      CX,DX
  617.                JNZ     NEXT_SIZE               ;If no, divide again.
  618.  
  619.                CLD                             ;Back to forward direction.
  620.                POP     DI                      ;Retrieve pointer.
  621.                ADD     DI,11                   ;Move to date field.
  622. DATE:          MOV     DX,DTA.FILE_DATE        ;Retrieve date.
  623.                MOV     AX,DX
  624.                MOV     CL,5                    ;Shift to lowest bits.
  625.                SHR     AX,CL
  626.                AND     AX,1111B                ;Mask off all but month.
  627.                MOV     CL,0FFH                 ;Flag as no leading zeros.
  628.                MOV     CH,"-"                  ;Delimiting character.
  629.                CALL    STORE_WORD              ;Store it.
  630.  
  631.                MOV     AX,DX                   ;Retrieve date.
  632.                AND     AX,11111B               ;Mask off all but day.
  633.                XOR     CL,CL                   ;Flag include leading zeros.
  634.                MOV     CH,"-"
  635.                CALL    STORE_WORD              ;Store it.
  636.  
  637.                MOV     AX,DX                   ;Retrieve date for last time.
  638.                MOV     CL,9
  639.                SHR     AX,CL                   ;Mask off all but year.
  640.                ADD     AX,80                   ;Adjust to ASCII.
  641.                CMP     AX,100                  ;Past year 2000?
  642.                JB      DISPLAY_DATE            ;If no, display. Else, adjust for
  643.                SUB     AX,100                  ; next century. (Planning ahead!)
  644. DISPLAY_DATE:  XOR     CL,CL                   ;Display leading zeros.
  645.                MOV     CH,SPACE
  646.                CALL    STORE_WORD              ;Store it.
  647.  
  648. TIME:          INC     DI                      ;Move to time field.
  649.                MOV     DX,DTA.FILE_TIME        ;Retrieve time.
  650.                MOV     AX,DX
  651.                MOV     CL,11                   ;Shift to hours bits.
  652.                SHR     AX,CL
  653.                PUSH    AX
  654.                CMP     AX,12                   ;Past noon?
  655.                JBE     MERIDIAN
  656.                SUB     AX,12                   ;If yes, adjust.
  657. MERIDIAN:      CMP     AX,0                    ;Midnight?
  658.                JNZ     NOT_MIDNIGHT
  659.                MOV     AX,12                   ;If yes, adjust.
  660. NOT_MIDNIGHT:  MOV     CL,0FFH                 ;Suppress leading zeros.
  661.                MOV     CH,":"
  662.                CALL    STORE_WORD              ;Store it.
  663.  
  664.                MOV     AX,DX                   ;Retrieve time.
  665.                MOV     CL,5                    ;Shift to minutes bits.
  666.                SHR     AX,CL
  667.                AND     AX,111111B              ;Mask off all but minutes.
  668.                XOR     CL,CL
  669.                POP     DX                      ;Retrieve hours.
  670.                MOV     CH,"p"                  ;Assume PM.
  671.                CMP     DX,12                   ;Is it PM?
  672.                JAE     PM
  673.                MOV     CH,"a"                  ;If no, AM.
  674.  
  675. PM:            CALL    STORE_WORD              ;Store it.
  676.                XOR     AL,AL
  677.                STOSB
  678.                MOV     SI,OFFSET RESULTS       ;Print out results
  679.                CALL    PRINT_STRING
  680.                MOV     SI,OFFSET CR_LF
  681.                CALL    PRINT_STRING
  682.                RET                             ;Done here.
  683.  
  684. ;-----------------------------------------------------------------------;
  685. ; Converts a two byte hex number to decimal followed by delimiter.      ;
  686. ; INPUT: AX = hex number; BL = 10; CH = delimiter character to store.   ;
  687. ;   CL = 0 if zeros are to be stored; CL = -1 if leading zeros ignored. ;
  688. ;   ES:DI points to storage.                                            ;
  689. ;-----------------------------------------------------------------------;
  690. STORE_WORD:    DIV     BL                      ;Divide by ten.
  691.                ADD     AX,"00"                 ;Convert to ASCII.
  692.                CMP     CL,0                    ;Are we to display leading zero?
  693.                JZ      STORE_IT                ;If yes, store as is.
  694.                CMP     AL,"0"                  ;Is it a leading zero?
  695.                JNZ     STORE_IT                ;If no, store it.
  696.                MOV     AL,SPACE                ;Else, store a space.
  697. STORE_IT:      STOSW
  698.                MOV     AL,CH                   ;Store delimiter character also.
  699.                STOSB
  700.                RET
  701.  
  702. ;----------------------------------------------;
  703. ; INPUT: DX = first row to write spaces.       ;
  704. ;----------------------------------------------;
  705. BLANK_LINE:    PUSH    DX
  706.                CALL    SET_CURSOR
  707.                MOV     CX,80 * 4
  708. NEXT_BLANK:    MOV     AX,0EH SHL 8 + SPACE    ;Write spaces via BIOS.
  709.                INT     10H
  710.                LOOP    NEXT_BLANK
  711.                POP     DX
  712.                CALL    SET_CURSOR
  713.                RET
  714.  
  715. ;----------------------------------------------;
  716. GET_DIR:       MOV     BYTE PTR [SI],"\"       ;DOS doesn't preface directory
  717.                INC     SI                      ; with slash so we must.
  718.                XOR     DL,DL
  719.                MOV     AH,47H                  ;Get current directory.
  720.                INT     21H
  721.                RET
  722.  
  723. CHANGE_DIR:    MOV     AH,3BH                  ;Change current directory.
  724.                INT     21H
  725.                RET
  726.  
  727. ;----------------------------------------------;
  728. SET_CURSOR:    XOR     BH,BH                   ;Video page zero.
  729.                MOV     AH,2                    ;Set cursor position.
  730.                INT     10H
  731.                RET
  732.  
  733. GET_CURSOR:    XOR     BH,BH
  734.                MOV     AH,3                    ;Get cursor position.
  735.                INT     10H
  736.                RET
  737.  
  738. ;----------------------------------------------;
  739. GET_KEY:       XOR     AH,AH                   ;Get a keystroke.
  740.                INT     16H
  741.                RET
  742.  
  743. CK_KEY:        MOV     AH,1                    ;ZR = 1 if no keystroke available
  744.                INT     16H                     ;ZR = 0 if keystroke is available
  745.                RET
  746.  
  747. CLEAR_IT:      CALL    GET_KEY
  748. CLEAR_KEY:     CALL    CK_KEY                  ;If any keystrokes available,
  749.                JNZ     CLEAR_IT                ; remove them.
  750.                RET
  751.  
  752. ;----------------------------------------------;
  753. WRITE_TTY:     MOV     AH,0EH                  ;Write TTY via BIOS.
  754.                INT     10H
  755. PRINT_STRING:  LODSB
  756.                OR      AL,AL                   ;ASCIIZ string.
  757.                JNZ     WRITE_TTY
  758.                RET
  759.  
  760. CURRENT_DIR    =       $
  761. WORKING_DIR    =       CURRENT_DIR + 68
  762. RESULTS        =       WORKING_DIR + 68
  763. DTA            =       RESULTS + 41
  764. TREE_LEVEL     =       DTA + SIZE MATCHING
  765. STACK_PTR      =       TREE_LEVEL + 100 + 256
  766. ZEROS          =       STACK_PTR
  767.  
  768. _TEXT          ENDS
  769.                END     START
  770.